﻿using MediatR;
using Microsoft.Extensions.Logging;
using Sgr.Application.Commands;
using Sgr.Domain.Entities;
using Sgr.Exceptions;
using Sgr.Identity.Services;
using Sgr.Security.VerifyCode;
using Sgr.UPMS.Domain.Organizations;
using Sgr.UPMS.Domain.Users;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Sgr.UPMS.Application.Commands.Organizations
{
    /// <summary>
    /// 组织机构注册命令处理器
    /// </summary>
    /// <remarks>
    /// 处理组织机构的注册流程，包括：
    /// 1. 输入验证
    /// 2. 验证码校验
    /// 3. 账号唯一性校验
    /// 4. 创建组织机构
    /// 5. 创建管理员用户
    /// </remarks>
    public class RegisterOrgCommandHadle : IRequestHandler<RegisterOrgCommand, CommandResult<bool>>
    {
        private readonly IOrganizationRepository _organizationRepository;
        private readonly IUserManage _userManage;
        private readonly IOrganizationManage _organizationManage;
        private readonly IUserRepository _userRepository;
        private readonly IPasswordHashService _passwordHashService;
        private readonly IVerifyCodeService _verifyCodeService;

        #region 常量定义

        private const string SUCCESS_MESSAGE = "组织机构注册成功";

        #endregion 常量定义

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="userManage">用户管理器</param>
        /// <param name="organizationManage">组织机构管理器</param>
        /// <param name="userRepository">用户仓储</param>
        /// <param name="organizationRepository">组织机构仓储</param>
        /// <param name="verifyCodeService">验证码服务</param>
        /// <param name="passwordHashService">密码哈希服务</param>
        public RegisterOrgCommandHadle(
            IUserManage userManage,
            IOrganizationManage organizationManage,
            IUserRepository userRepository,
            IOrganizationRepository organizationRepository,
            IVerifyCodeService verifyCodeService,
            IPasswordHashService passwordHashService)
        {
            _userManage = userManage ?? throw new ArgumentNullException(nameof(userManage));
            _organizationManage = organizationManage ?? throw new ArgumentNullException(nameof(organizationManage));
            _userRepository = userRepository ?? throw new ArgumentNullException(nameof(userRepository));
            _organizationRepository = organizationRepository ?? throw new ArgumentNullException(nameof(organizationRepository));
            _verifyCodeService = verifyCodeService ?? throw new ArgumentNullException(nameof(verifyCodeService));
            _passwordHashService = passwordHashService ?? throw new ArgumentNullException(nameof(passwordHashService));
        }

        /// <summary>
        /// 处理组织机构注册命令
        /// </summary>
        /// <param name="request">注册命令请求</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>注册结果</returns>
        public async Task<CommandResult<bool>> Handle(RegisterOrgCommand request, CancellationToken cancellationToken)
        {
            // 1. 检查验证码
            if (!await ValidateVerifyCode(request, cancellationToken))
            {
                return CommandResult.Invalid<bool>(Constant.INVALID_VERIFYCODE_MESSAGE);
            }

            // 2. 验证账号唯一性
            var uniqueCheckResult = await ValidateAccountUniqueness(request, cancellationToken);
            if (!uniqueCheckResult.IsComply)
            {
                return CommandResult.Invalid<bool>(uniqueCheckResult.Message);
            }

            // 创建组织
            var organization = await _organizationManage.CreateNewAsync(
                null, // 新建组织机构时ID为null,由系统自动生成
                request.Name,
                "",
                "",
                null, // 父级ID为null表示顶级组织
                cancellationToken);

            // 设置联系信息
            if (request.AuthenticationType == UserAuthenticationType.PhoneNumber)
                organization.Phone = request.Account;
            else if (request.AuthenticationType == UserAuthenticationType.Email)
                organization.Email = request.Account;

            await _organizationRepository.InsertAsync(organization, cancellationToken);

            // 创建管理员用户
            string userName = "";
            if (!string.IsNullOrWhiteSpace(request.UserName))
                userName = request.UserName;
            else
                userName = await GenerateUniqueLoginNameAsync(_userManage, cancellationToken);

            var user = await _userManage.CreateNewAsync(
                userName,
                _passwordHashService,
                request.LoginPassword ?? Constant.DEFAULT_PASS_WORD,
                true,               // 设置为管理员
                organization.Id,    // 关联到新创建的组织
                cancellationToken);

            // 绑定验证账号
            BindUserAccount(user, request.Account, request.AuthenticationType);

            user.DifferenceUpdateRoles(new long[] { Constant.SYSTEM_ADMIN_ROLE_ID }, true);

            await _userRepository.InsertAsync(user, cancellationToken);

            return CommandResult.Success(true, SUCCESS_MESSAGE);
        }

        #region 私有辅助方法

        internal static async Task<string> GenerateUniqueLoginNameAsync(IUserManage userManage, CancellationToken cancellationToken)
        {
            int maxAttempts = 20;

            for (int i = 0; i < maxAttempts; i++)
            {
                // 生成UUID并取前8位
                string uuid = Guid.NewGuid().ToString("N").Substring(0, 8);
                string candidateName = $"u{uuid}";

                var checkResult = await userManage.ValidateLoginNameUniquenessAsync(candidateName, null, cancellationToken);
                if (checkResult.IsComply)
                    return candidateName;
            }

            throw new DomainException("无法生成唯一的账号名称，请稍后重试");
        }

        /// <summary>
        /// 验证验证码
        /// </summary>
        private async Task<bool> ValidateVerifyCode(RegisterOrgCommand request, CancellationToken cancellationToken)
        {
            return await _verifyCodeService.VerifyAsync(
                request.AuthenticationType == UserAuthenticationType.PhoneNumber ? ReceiverType.Phone : ReceiverType.Email,
                request.Account,
                request.VerificationPurpose,
                request.VerificationCode,
                true,
                cancellationToken);
        }

        /// <summary>
        /// 验证账号唯一性
        /// </summary>
        private async Task<DomainRuleCheckResult> ValidateAccountUniqueness(
            RegisterOrgCommand request,
            CancellationToken cancellationToken)
        {
            return request.AuthenticationType switch
            {
                UserAuthenticationType.PhoneNumber =>
                    await _userManage.ValidatePhoneNumberUniquenessAsync(request.Account, null, cancellationToken),
                UserAuthenticationType.Email =>
                    await _userManage.ValidateEmailUniquenessAsync(request.Account, null, cancellationToken),
                _ => DomainRuleCheckResult.Fail("不支持的验证类型")
            };
        }

        /// <summary>
        /// 绑定用户账号
        /// </summary>
        private static void BindUserAccount(User user, string account, UserAuthenticationType authenticationType)
        {
            switch (authenticationType)
            {
                case UserAuthenticationType.PhoneNumber:
                    user.BindPhoneNumber(account, true);
                    break;

                case UserAuthenticationType.Email:
                    user.BindUserEmail(account, true);
                    break;

                default:
                    throw new ArgumentException("不支持的验证类型", nameof(authenticationType));
            }
        }

        #endregion 私有辅助方法
    }
}